#include "tracing.h"
GENERIK_TRACER_GLOBAL;

#include "any.h"

#include <iostream>
#include <list>
#include <stdlib.h>
#include <unistd.h>

struct arg
{
	std::string _opt, _brief, _detail;
	generik::any _target;
	
	template <typename TYPE>
	arg(const std::string& opt, const std::string& brief, const std::string& detail, TYPE* target)
	: _opt(opt), _brief(brief), _detail(detail)
	, _target(target)
	{}
	char flag()
	{
		return _opt[0];
	}
	void set(const std::string& value)
	{
		_target.set(value);
	}
	/*
	void set()
	{
		_target.set();
	}
	*/
};

struct arglist
{
	std::list<arg> args;
	
	arg* find(char flag)
	{
		std::list<arg>::iterator i = args.begin();
		std::list<arg>::iterator end = args.end();
		for (; i != end; ++i)
		{
			char f = i->flag();
			if (f == flag)
			{
				arg* v = &(*i);
				return v;
			}
		}
		return 0;
	}
	
	bool process(char flag)
	{
		arg* _found = find(flag);
		if (_found)
		{
			_found->set("true");
			return true;
		}
		return false;
	}
	
	bool process(char flag, const std::string& value)
	{
		arg* _found = find(flag);
		if (_found)
		{
			_found->set(value);
			return true;
		}
		return false;
	}
	
	template <typename TYPE>
	void add(const std::string& opt, const std::string& brief, const std::string& detail, TYPE* target)
	{
		args.push_back(arg(opt, brief, detail, target));
	}
	
	/*
	void add(const std::string& opt, const std::string& brief, const std::string& detail)
	{
		args.push_back(arg(opt, brief, detail));
	}
	*/
	
	std::string getoptstr()
	{
		std::string result;
		std::list<arg>::iterator i = args.begin();
		std::list<arg>::iterator end = args.end();
		for (; i != end; ++i)
		{
			result += i->_opt;
		}
		return result;
	}
	
	std::string usage(const std::string& progname)
	{
		std::stringstream result;
		result<<"Usage: "<<progname<<" ";
		std::list<arg>::iterator end = args.end();
		std::list<arg>::iterator i = args.begin();
		for (; i != end; ++i)
		{
			result<<i->_brief<<" ";
		}
		result<<"\nwhere\n";
		i = args.begin();
		for (; i != end; ++i)
		{
			result<<"\t"<<i->_brief<<" "<<i->_detail<<"\n";
		}
		return result.str();
	}
};

int main(int argc, char** argv)
{
	GENERIK_TRACER;
	
	bool help = false;
	int x = 456;
	std::string y = "blah";
	
	arglist list;
	list.add("h",  "[-h/?]", "shows this help information"), &help);
	list.add("i:", "[-i <int>]", "sets the integer x value", &x);
	list.add("s:", "[-s <string>]", "sets the string y value", &y);
	
	std::string optstr = list.getoptstr();
	GENERIK_TRACE_VALUE(optstr);
	int opt = -1;
	const char* os = optstr.c_str();
	while ( (opt = getopt(argc, argv, os)) != -1 )
	{
		bool result = optarg ? list.process(opt, optarg) : list.process(opt);
		if (!result)
		{
			GENERIK_ERROR("could not parse the argument");
			GENERIK_ERROR(list.usage(argv[0]));
			exit(-1);
		}
	}
	
	if (help)
	{
		std::cout<<list.usage(argv[0])<<std::endl;
		exit(-1);
	}
	
	std::cout<<"x is "<<x<<std::endl;
	std::cout<<"y is "<<y<<std::endl;
	
	return 0;
}



